home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Tele / C / Comet2.1.3.cpt / Comet / tftp_srv.c < prev    next >
Text File  |  1991-05-06  |  12KB  |  524 lines

  1. /*  Copyright 1984 by the Massachusetts Institute of Technology  */
  2.  
  3. /*
  4.     Copyright Cornell University 1986.  All rights are reserved.
  5.  
  6.     As of 4/10/86:
  7.     This source file may have no changes from the M.I.T original
  8.     other than this notice; but it has been tested as part of 
  9.     Cornell's Aztec-C port.  See notice.h
  10. */
  11.  
  12. /*  See permission and disclaimer notice in file "notice.h"  */
  13.  
  14. #include    <notice.h>
  15. #include    "tftp.h"
  16.  
  17. extern int tntftp(), tntfdn();
  18.  
  19. extern int (*tfs_alert)();
  20. extern int (*tfs_done)();
  21.  
  22. extern char macfile[];            /* for Macintosh file name translation */
  23.  
  24. extern int ntftps;
  25.  
  26.  
  27. extern int tfstate;
  28. extern long refusedt;            /*  time of most recent transfer refusal  */
  29.  
  30. extern unsigned NDEBUG;
  31.  
  32. /* the tftp server code */
  33.  
  34. /*  Modified 12/23/83 to upcall a "done" function when the transfer is
  35.     complete.  Modified 1/11/84 to detect and discard duplicate requests
  36.     to open a tftp connection.  Fixed file open calls to use only binary mode
  37.     (was making netascii transfers fail); fixed bug in counting number of 
  38.     tftp connections in progress; changed calls to send error packets to
  39.     use incoming packet and socket number where appropriate, 1/13/84.
  40.     Added test to discard duplicate requests that match current connections,
  41.     that arrived before user refused a request or before discovery that
  42.     file can't be transferred.
  43.                       <J. H. Saltzer>
  44.     1/24/84 - added octet mode which is the same as image mode.
  45.                      <John Romkey>
  46.     3/21/84 - corrected several places in the code where cn->tf_expected
  47.     was referenced as cn->tf_expect and caused problems with the new
  48.     compiler.
  49.                      <John Romkey>
  50.     4/12/84 - in tfsread() fixed call to udp_alloc() which was missing
  51.     the option length parameter.
  52.                     <John Romkey>
  53.     12/21/84 - in tfsread() fixed buffer swapping code to prevent loss
  54.     of one packet buffer on each transfer.
  55.                     <J. H. Saltzer>
  56. */
  57.  
  58. #define    MAXTFTPS    1
  59.  
  60. UDPiopb tfspb;                /* control block for TFTP listener socket */
  61. char tfsbuf[MACUDPLEN];        /* MacTCP read buffer */
  62. StreamPtr tfsstream;        /* stream ptr for listener socket */
  63. int tfs_read_req;            /* server read requests */
  64. int tfs_read_comp;            /* server read completions */
  65. int tfsdata;                /* data has arrived */
  66.  
  67. struct tfconn tfsconn;        /* tftp control connection struct */
  68. struct tfconn tftpconn;        /* tftp transfer connection struct */
  69.  
  70. UDPiopb tftppb;                /* control block for TFTP transfer socket */
  71. char tftpbuf[MACUDPLEN];    /* MacTCP read buffer */
  72. StreamPtr tftpstream;        /* stream ptr for transfer socket */
  73. int tftp_read_req;            /* server read requests */
  74. int tftp_read_comp;            /* server read completions */
  75. int tftpdata;                /* data has arrived */
  76.  
  77. extern char * malloc();
  78. unsigned long getmyA5();
  79.  
  80. /* ioCompletion routine for the tftp listener on the server socket */
  81.  
  82. void tfs_read_done(udp_read)
  83. UDPiopb *udp_read;
  84. {
  85.     unsigned long oldA5;
  86.  
  87.     oldA5 = getmyA5(); 
  88.  
  89.     tfsdata = TRUE;
  90.     tfs_read_comp++;
  91.     
  92.     setA5(oldA5);
  93. }
  94.  
  95.  
  96. /* ioCompletion routine for the tftp transfer socket */
  97.  
  98. void tftp_read_done(udp_read)
  99. UDPiopb *udp_read;
  100. {
  101.     unsigned long oldA5;
  102.  
  103.     oldA5 = getmyA5(); 
  104.  
  105.     tftpdata = TRUE;
  106.     tftp_read_comp++;
  107.     
  108.     setA5(oldA5);
  109. }
  110.  
  111. udp_release()
  112. {
  113.     UDPiopb relPB;
  114.     OSErr errcode;
  115.     
  116.     if (!tfsstream)
  117.         return(-1);
  118.         
  119.     relPB.ioCRefNum = ipp_refnum;
  120.     relPB.csCode = UDPRelease;
  121.     relPB.udpStream = tfsstream;
  122.  
  123.     if (errcode = PBControl(&relPB, (Boolean) FALSE))
  124.         error("udp release failed");
  125. }
  126.  
  127.  
  128. /* mtcp_tfsinit(alert, done) - initialize the tftp server. This opens a UDP
  129.      connection but does not turn on the server. That needs to done by
  130.      an explicit call to tfs_on().
  131.  
  132.     alert() is a function which the server will call whenever it receives
  133.     request for a transfer. This function will be called int he following
  134.     way:
  135.         alert(ip_addr, file_name, direction)
  136.  
  137.     alert() should return TRUE if it wishes to allow the transfer and
  138.     FALSE otherwise.  done() is a function that the server will
  139.     call to    inform the invoker that this file transfer is complete or
  140.     aborted.
  141. */
  142.  
  143. mtcp_tfsinit(alert, done)
  144.     int (*alert)();
  145.     int (*done)(); 
  146. {
  147.     OSErr errcode;
  148.     extern short macipopen;
  149.     
  150.     if (!macipopen) {
  151.         if (macip_init())
  152.             return(-1);
  153.     }
  154.     tfspb.ioCRefNum = ipp_refnum;
  155.     tfspb.csCode = UDPCreate;
  156.     tfspb.csParam.create.rcvBuff = &tfsbuf[0];
  157.     tfspb.csParam.create.rcvBuffLen = MACUDPLEN;
  158.     tfspb.csParam.create.notifyProc = (ProcPtr) udp_event;
  159.     tfspb.csParam.create.localPort = TFTPSOCK;
  160.  
  161.     if (errcode = PBControl(&tfspb, (Boolean) FALSE)) {
  162.         if (errcode != duplicateSocket)
  163.             /* skip message if socket already opened */
  164.             error("tftp: UDPCreate failed");
  165.         return(-1);
  166.     }
  167.     tfsstream = tfspb.udpStream;
  168.     exit_hook(udp_release);
  169.     
  170.     if (mttfmkcn(&tfsconn, PUT, ASCII)) {
  171.         /* make one connection block */
  172.         return(-1);
  173.     }
  174.     tfsconn.stream = tfsstream;
  175.  
  176.     tfspb.csCode = UDPRead;
  177.     tfspb.ioCompletion = tfs_read_done;
  178.     tfspb.csParam.receive.timeOut = 0;
  179.     if (errcode = PBControl(&tfspb, (Boolean) TRUE)) {
  180.         error("tftp: no UDPRead");
  181.     }
  182.     tfs_read_req++;
  183.     
  184.     tfs_done = done;
  185.     tfs_alert = alert;
  186.     return(FALSE);
  187. }
  188.  
  189. /* handle an incoming tftp packet. This involves opening a udp connection
  190.     (immediately so that we can report errors). If the server is OFF
  191.     then the tftp will be refused; otherwise more checking will be done.
  192.     Call the alert function and verify that the "user" wishes to allow
  193.     the tftp. Report an error if not. Finally, spawn a task to oversee
  194.     the tftp and cleanup when it's done.
  195. */
  196. ip_addr tftphost;        /* to check for duplicate connection request */
  197. udp_port tftpport;        /* ditto */
  198.  
  199. mtcp_tfshnd(ptreq, len, host, port, time)
  200.     struct tfreq *ptreq;
  201.     unsigned len;
  202.     ip_addr host;
  203.     udp_port port;
  204.     unsigned short time;
  205. {
  206.     unsigned nport;
  207.     struct tfconn *cn = &tftpconn;
  208.     char *file, *smode, *tmp;
  209.     unsigned mode;
  210.     OSErr errcode;
  211.     
  212.     /* If there is already a connection like this one, ignore duplicate 
  213.         request.
  214.  
  215.     if (udp_ckcon(host, port)) { 
  216.         return(0);
  217.     }
  218.  */
  219.      /* since we don't have access to UDP with MacTCP we maintain this manually */
  220.      if (host == tftphost && port == tftpport) { 
  221.         return(0);
  222.     }
  223.     
  224.  
  225.     /*  If we refused a connection since this request got enqueued,
  226.     assume this is a duplicate and discard it, so we don't bother the
  227.     user with a duplicate question.  (If we are unlucky, this might be
  228.     a request from somewhere else that arrived while the user was
  229.     thinking over the previous request.  Tough; somewhere else will
  230.     just have to try again.)
  231.     
  232.   */
  233.  
  234.     if (refusedt > time) {
  235.         return(0);
  236.     }
  237.   
  238.     /*  The next question:  Do we have room to do this transfer?  */
  239.  
  240.     if (ntftps >= MAXTFTPS) {
  241.         mtcp_tfrpyerr(&tfsconn, ERRTXT, "Too many connections.");
  242.         return(0);
  243.     }
  244.  
  245.     /*  OK, let's check over the request more carefully. */
  246.  
  247.     if (ptreq->tf_op > WRQ) {
  248. #ifdef TFTPDEBUG
  249.         if (NDEBUG & INFOMSG|NETERR|PROTERR)
  250.             printf("TFTP SERVER: bad tftp opcode %u\n", ptreq->tf_op);
  251. #endif
  252.         return(0);
  253.     }
  254.     file = &ptreq->tf_name[0];
  255.     smode = file + strlen(file) + 1;
  256.  
  257.     for (tmp = smode; *tmp; tmp++)
  258.         if (*tmp >= 'A' && *tmp <= 'Z')
  259.             *tmp += 32;
  260.  
  261.     if (strcmp(smode, "image") == 0) 
  262.         mode = IMAGE;
  263.     else if (strcmp(smode, "octet") == 0) 
  264.         mode = IMAGE;
  265.     else if (strcmp(smode, "netascii") == 0) 
  266.         mode = ASCII;
  267.     else {
  268. #ifdef TFTPDEBUG
  269.         if (NDEBUG & INFOMSG|NETERR|PROTERR)
  270.             printf("TFTP SERVER:  Bad mode %s in req\n", smode);
  271. #endif
  272.         mtcp_tfrpyerr(&tfsconn, ERRTXT, "Bad mode");
  273.         return(0);
  274.     }
  275.  
  276.     if (tfstate == OFF) {
  277.         mtcp_tfrpyerr(&tfsconn, ERRTXT,"Transfers are not being accepted.");
  278.         return(0);
  279.     }
  280.  
  281.     if ((*tfs_alert)(host, file, ptreq->tf_op == RRQ ? PUT : GET) == 0) {
  282.         mtcp_tfrpyerr(&tfsconn, ERRTXT, "Transfer refused.");
  283.         refusedt = time;
  284.         return(0);
  285.     }
  286.  
  287.     /*  It looks safe to try to open a connection.  */
  288.  
  289.     if (mttfmkcn(cn, PUT, ASCII)) {
  290.         /*  Direction is a dummy for now  */
  291.         error("TFTP SERVER:  Can't make connection, ignoring request");
  292.         return(0);
  293.     }
  294.  
  295. #ifdef UDPFUNC
  296.     cn->tf_udp = udp_open(host, port, udp_socket(), tftp_read_done, cn);
  297.  
  298.     if (cn->tf_udp == NULL) {
  299.         error("TFTP SERVER: Can't open udp connection, ignoring request");
  300.         mtcp_tfcleanup(cn);
  301.         return(0);
  302.     }
  303. #else
  304.     tftppb.ioCRefNum = ipp_refnum;
  305.     tftppb.csCode = UDPCreate;
  306.     tftppb.csParam.create.rcvBuff = &tftpbuf[0];
  307.     tftppb.csParam.create.rcvBuffLen = MACUDPLEN;
  308.     tftppb.csParam.create.notifyProc = (ProcPtr) udp_event;
  309.     tftppb.csParam.create.localPort = udp_socket();
  310.  
  311.     if (errcode = PBControl(&tftppb, (Boolean) FALSE)) {
  312.             error("tftp: couldn't open UDP");
  313.     }
  314.     cn->tf_udp = &tftppb;
  315.     cn->tf_host = host;
  316.     cn->tf_port = port;
  317.     tftpstream = tftppb.udpStream;
  318.     cn->stream = tftpstream;
  319.  
  320.     /* and set up a read */
  321.     tftppb.csCode = UDPRead;
  322.     tftppb.ioCompletion = tftp_read_done;
  323.     tftppb.csParam.receive.timeOut = 0;
  324.     if (errcode = PBControl(&tftppb, (Boolean) TRUE)) {
  325.         error("tftp: no UDPRead");
  326.     }
  327. #endif
  328.  
  329.     cn->tf_mode = mode;
  330.     cn->tf_state = INIT;
  331.     macpath(file, &macfile[0]);
  332.     if (ptreq->tf_op == RRQ) {
  333.         cn->tf_dir = PUT;
  334.         cn->tf_haveport = TRUE;
  335.  
  336.         cn->tf_fd = fopen(&macfile[0], "r");
  337.         if (cn->tf_fd == NULL) {
  338. #ifdef TFTPDEBUG
  339.             if (NDEBUG & NETERR|PROTERR)
  340.                 printf("couldn't open file\n");
  341. #endif
  342.             mtcp_tfudperr(cn, FNOTFOUND, NULL);
  343.             refusedt = cticks;
  344.             mtcp_tfcleanup(cn);
  345.             (*tfs_done)(OFF); 
  346.             return(0);
  347.         }
  348.         tfssend(cn);
  349.     }
  350.     else {
  351.         cn->tf_dir = GET;
  352.         cn->tf_haveport = TRUE;
  353.         cn->tf_fd = fopen(&macfile[0], "w");
  354.         if (cn->tf_fd == NULL) {
  355.             /* error("couldn't open file"); */
  356.             mtcp_tfudperr(cn, ACCESS, NULL);
  357.             refusedt = cticks;
  358.             mtcp_tfcleanup(cn);
  359.             (*tfs_done)(OFF);
  360.             return(0);
  361.         }
  362.         tfsrcv(cn);
  363.     }
  364.     ntftps++;
  365.     tftphost = host;
  366.     tftpport = port;
  367. }
  368.  
  369.  
  370. tfsrcv(cn)
  371. struct tfconn *cn; 
  372. {
  373.     switch (cn->tf_state) {
  374.         case INIT: {
  375.             cn->tf_expected = 1;
  376.             mtcp_tfsndack(cn, 0);
  377.             cn->tf_state = DATAWAIT;
  378.             break;
  379.         }
  380.         case RCVDATA: {
  381.             cn->tf_state = DATAWAIT;
  382.             break;
  383.         }
  384.         case RCVLASTDATA: {
  385.             mtcp_tfcleanup(cn);
  386.             (*tfs_done)(ON);
  387.             ntftps--;
  388.             tftphost = 0;
  389.             tftpport = 0;
  390.             break;
  391.         }
  392.         case TIMEOUT: {
  393. #ifdef TFTPDEBUG
  394.             if (NDEBUG & TMO)
  395.                 printf("TFTP: Host not responding, giving up\n");
  396. #endif
  397.             mtcp_tfudperr(cn, ERRTXT,
  398.                  "Retry limit exceeded, giving up");
  399.             mtcp_tfcleanup(cn);
  400.             (*tfs_done)(OFF);
  401.             ntftps--;
  402.             tftphost = 0;
  403.             tftpport = 0;
  404.             break;
  405.         }
  406.         default: {
  407.             /* unknown state, kill it */
  408.             mtcp_tfcleanup(cn);
  409.             (*tfs_done)(OFF);
  410.             ntftps--;
  411.             tftphost = 0;
  412.             tftpport = 0;
  413.             break;
  414.         }
  415.     }
  416. }
  417.  
  418.  
  419. /* vars belong in conn struct */
  420.  
  421. int flen;
  422. int tftpdone;
  423. char * pfill;
  424. char * psnd;
  425.  
  426. tfssend(cn)
  427. struct tfconn *cn; 
  428. {
  429.     switch (cn->tf_state) {
  430.         case INIT: {
  431.             /* no connection, initialize */
  432.         
  433.             flen = NORMLEN;
  434.             tftpdone = 0;
  435.             cn->tf_expected = 0;
  436.         
  437.             psnd = cn->tf_outp;                    /* psnd is tftp_util's buffer */
  438.             pfill = malloc(NORMLEN);              /* pfill is ours */
  439.             if (pfill == NULL) {
  440.                 mtcp_tfudperr(cn, ERRTXT, "Couldn't allocate packet.");
  441. #ifdef TFTPDEBUG
  442.                 if (NDEBUG & NETERR|PROTERR)
  443.                     printf("tfsread: couldn't allocate pfill\n");
  444. #endif
  445.                 mtcp_tfcleanup(cn);
  446.                 (*tfs_done)(OFF);
  447.             }
  448.             /* fill up a data packet */
  449.             fillpacket(cn);
  450.             /* and fall through to send the first packet */
  451.         }
  452.         case RCVACK: {
  453.             cn->tf_expected++;
  454.  
  455.             /* Check if we're done */
  456.             if (tftpdone) {
  457.                 mtcp_tfcleanup(cn);
  458.                 (*tfs_done)(ON);
  459.                 free(pfill);
  460.                 ntftps--;
  461.                 tftphost = 0;
  462.                 tftpport = 0;
  463.                 break;
  464.             }
  465.  
  466.             /* If not, resume the loop */
  467.             psnd = pfill;            /* prepare to switch */
  468.             pfill = cn->tf_outp;    /* take tftp_util's buffer */
  469.             cn->tf_outp = psnd;        /* our buffer to tftp_util */
  470.             mtcp_tfsndata(cn, flen);
  471.             if (flen < NORMLEN) 
  472.                 tftpdone = 1;
  473.             else
  474.                 fillpacket(cn);        /* fill the next packet as we wait for ACK */
  475.             break;
  476.         }
  477.         case TIMEOUT: {
  478. #ifdef TFTPDEBUG
  479.             if (NDEBUG & TMO)
  480.                 printf("TFTP: Host not responding, giving up\n");
  481. #endif
  482.             mtcp_tfudperr(cn,
  483.                 ERRTXT, "Retry limit exceeded, giving up");
  484.             mtcp_tfcleanup(cn);
  485.             (*tfs_done)(OFF);
  486.             free(pfill);
  487.             ntftps--;
  488.             tftphost = 0;
  489.             tftpport = 0;
  490.             break;
  491.         }
  492.         default: {
  493.             /* something's wrong here */
  494.             mtcp_tfcleanup(cn);
  495.             (*tfs_done)(ON);
  496.             free(pfill);
  497.             ntftps--;
  498.             tftphost = 0;
  499.             tftpport = 0;
  500.             break;
  501.         }
  502.     }
  503. }
  504.  
  505.  
  506. fillpacket(cn)
  507. struct tfconn *cn; 
  508. {
  509.     register char * datap;
  510.     register char * endp;
  511.     
  512.     datap = (char *) tftp_data(pfill);
  513.     
  514.     flen = fread(datap, 1, NORMLEN, cn->tf_fd);
  515.     if (cn->tf_mode == ASCII) {
  516.         /* translate CR's to LF's */
  517.         
  518.         for (endp = datap + flen; datap < endp; datap++) {
  519.             if (*datap == 0x0d)
  520.                 *datap = 0x0a;
  521.         }
  522.     }
  523.     cn->tf_size += flen;
  524. }